Skip to content

feat(test-classifier): sandboxed OBSERVED runs via smolvm (control plane + plan) - #65

Open
fg-nava wants to merge 2 commits into
mainfrom
feat-smolvm-sandbox
Open

feat(test-classifier): sandboxed OBSERVED runs via smolvm (control plane + plan)#65
fg-nava wants to merge 2 commits into
mainfrom
feat-smolvm-sandbox

Conversation

@fg-nava

@fg-nava fg-nava commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

What

Opt-in sandbox control plane that runs OBSERVED (AI_RUN_SUITE=1) inside a disposable on-device smolvm VM, plus the design doc behind it. Resolves the no-sandbox risk: OBSERVED installs and runs a PR branch's code on the laptop with the developer's full ambient creds and litters the working tree.

AI_SANDBOX=1 AI_RUN_SUITE=1 test-classifier --pr 42 --submit

Implementation

scripts/sandbox-run.sh — the control plane / trust boundary:

  • stages a clean copy of the repo at HEAD into a 0700 temp dir mounted at /workspace — never the real checkout, so artifacts stay ephemeral and are removed on teardown (no mess);
  • writes a 0600 env-file with only the vars the classifier reads + provider keys (smolvm has no --env flag, so secrets stay off the command line); sourced in-VM;
  • copies the resolved tool's CLI config dir (~/.claude / ~/.codex / gh) into a staged HOME so the CLI authenticates in-guest;
  • ephemeral smolvm machine run with --net + a strict --allow-host allowlist (override via AI_SANDBOX_ALLOW_HOSTS);
  • trap cleanup EXIT INT TERM shreds the env-file + removes staging even on interrupt; preflight fails closed if smolvm is absent (no silent unsandboxed fallback).

Dispatcher routes OBSERVED+AI_SANDBOX=1 through the control plane, which re-invokes the dispatcher in-VM with AI_SANDBOX_ACTIVE=1 (recursion guard). INFERRED is never routed; CI unchanged.

DocsLOCAL_TEST_CLASSIFIER.md gains a Sandboxed OBSERVED section; SANDBOXED_OBSERVED.md is the full design.

Tested vs. not — read this

smolvm is not installed in my environment, so host-side logic is verified but not the in-VM execution:

  • ✅ routing matrix, env-file contents, staging layout, allowlist assembly, teardown leaves nothing behind, preflight fails closed.
  • ⚠️ Unverified (Phase-0 spikes): exit-code propagation from machine run; whether a copied ~/.claude/~/.codex authenticates after the HOME remap; Playwright browser-mode in-guest.

Scope

Opt-in, default off — nothing changes for existing runs. Not for merge yet — review of approach + implementation; in-VM path needs a real smolvm run first.

fg-nava added 2 commits June 24, 2026 10:57
Design doc (no implementation) for running OBSERVED (AI_RUN_SUITE=1) inside a
disposable on-device smolvm VM instead of directly on the developer's machine.

Resolves the no-sandbox risk flagged in LOCAL_TEST_CLASSIFIER.md: OBSERVED
installs + runs a PR branch's code with the developer's full ambient creds and
leaves build artifacts in the working tree.

Decisions captured: credentials cross via an ephemeral 0600 env-file + a copied
per-tool CLI config dir in the mount (no --env flag in smolvm; secrets kept off
the command line); strict --allow-host egress allowlist; ephemeral machine run
only (no named VMs); strict stage→run→teardown lifecycle with trap-based cleanup
and secret shredding. Documents the undocumented-smolvm gaps as spikes to
de-risk (exit-code propagation, browser-mode in-guest, cred-dir copy), and a
phased delivery where each phase is its own approval-gated PR.
Implements Phase 1 of the smolvm sandbox plan: an opt-in control plane that
runs OBSERVED (AI_RUN_SUITE=1) inside a disposable on-device smolvm VM instead
of directly on the developer's machine.

scripts/sandbox-run.sh (the control plane / trust boundary):
  • stages a CLEAN copy of the repo at HEAD into a 0700 temp dir mounted at
    /workspace — never the real checkout, so install artifacts (node_modules/,
    browsers, caches) stay ephemeral and vanish on teardown;
  • writes a 0600 env-file with ONLY the vars the classifier reads (AI_REVIEW_*,
    GH_TOKEN, METRICSAI_*, provider API keys) — smolvm has no --env flag, so
    secrets stay off the command line; sourced in-VM, never argv;
  • copies the RESOLVED tool's CLI config dir (~/.claude / ~/.codex / gh) into a
    staged HOME so claude/codex authenticate in-guest (key- or OAuth-based);
  • runs an ephemeral  with --net + a strict --allow-host
    allowlist (GitHub, provider, metricsai incl. the googleusercontent 302 hop,
    package registries; override via AI_SANDBOX_ALLOW_HOSTS);
  • trap cleanup EXIT INT TERM shreds the env-file and removes the staging dir
    even on interrupt; preflight fails CLOSED if smolvm is absent (no silent
    unsandboxed fallback).

dispatcher: routes OBSERVED+AI_SANDBOX=1 through the control plane, which
re-invokes the dispatcher in-VM with AI_SANDBOX_ACTIVE=1 set (recursion guard).
INFERRED is never routed (it executes nothing); CI path unchanged.

docs: LOCAL_TEST_CLASSIFIER.md gains a 'Sandboxed OBSERVED' section; the design
doc's status moves to Phase-1-implemented with Phase-0 spikes still pending a
real smolvm install.

Tested host-side (smolvm not installed here, so the in-VM path is unverified —
that's the Phase-0 spike): routing matrix (in-VM guard / INFERRED / OBSERVED+
sandbox / OBSERVED-no-sandbox all correct), env-file contents, staging layout,
allowlist assembly, and teardown leaving nothing behind.
@fg-nava fg-nava changed the title docs(test-classifier): plan for sandboxed OBSERVED runs via smolvm feat(test-classifier): sandboxed OBSERVED runs via smolvm (control plane + plan) Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant